package demo.messaging.client.ui;

import java.util.ArrayList;
import java.util.List;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;

import demo.messaging.client.core.ApplicationContext;
import demo.messaging.client.core.ClientManager;
import demo.messaging.client.core.IMessageEventListener;
import demo.messaging.client.core.MessageEvent;
import demo.messaging.client.core.MessageEvent.EnumMessageEventType;
import demo.messaging.common.ServiceException;
import demo.util_ui.client.ui.SimpleDialog;

public class MessagingEntryPoint implements EntryPoint, IMessageEventListener {

	private static String MAIN_DIV = "mainDiv";

	private final ClientManager clientManager = new ClientManager();

	private final List<IMessagingPlugin> plugins = new ArrayList<IMessagingPlugin>();

	private final Label pageTitle = new Label("Welcome");

	private final SimpleDialog infoDialog = new SimpleDialog();

	private final SimpleDialog errorDialog = new SimpleDialog();

	private final LoginUI loginUI = new LoginUI();

	private final MeettingUI meetingUI = new MeettingUI();

	private AbstractPluginUI activePluginUI = null;

	private final SimpleDialog reconnectDialog = new SimpleDialog() {

		@Override
		protected void onCloseButtonClicked() {
			Window.Location.replace("index.html");

		};
	};

	private final SimpleDialog notifyUserQuitDialog = new SimpleDialog() {

		@Override
		protected void onCloseButtonClicked() {
			gotoMeetingUI();
		};
	};

	private final IMessageEventListener errorListener = new IMessageEventListener() {
		@Override
		public void onMessageEvent(final MessageEvent event) {
			if (null != event.getThrowable()) {

				if (event.getThrowable() instanceof ServiceException) {
					ServiceException serviceException = (ServiceException) event
							.getThrowable();

					if (ServiceException.LOST_CONNECTION
							.equals(serviceException.getErrorId())) {
						MessagingEntryPoint.this.reconnectDialog.showError(
								"Sorry, there is a problème!", serviceException
										.getMessage());
					} else {
						showError(serviceException.getMessage());
					}
				} else {
					showError(event.getThrowable().getMessage());
				}
			}
		}
	};

	public MessagingEntryPoint() {
		ApplicationContext.putBean(ClientManager.BEAN_ID, this.clientManager);

		this.clientManager.getEventListeners().add(this.loginUI);
		this.clientManager.getEventListeners().add(this.meetingUI);
		this.clientManager.getEventListeners().add(
				this.meetingUI.getWaitInviteResponseDialog());
		this.clientManager.getEventListeners().add(
				this.meetingUI.getInviteNotificationDialog());

		this.clientManager.getEventListeners().add(this.errorListener);
		this.clientManager.getEventListeners().add(this);

		this.clientManager.getEventListeners().add(this.errorListener);

	}

	/**
	 * A subclass can add the plugin to be managed.
	 * @param plugin
	 */
	protected void addPlugin(final IMessagingPlugin plugin) {
		this.plugins.add(plugin);
	}

	private void deactivateActivePluginUI() {
		if (this.activePluginUI != null) {
			this.activePluginUI.deactivate(this.clientManager);
			this.activePluginUI = null;
		}
	}

	private IMessagingPlugin findPluginForGame(final String gameChoice) {
		for (IMessagingPlugin plugin : this.plugins) {
			if (plugin.getClass().getName().equals(gameChoice)) {
				return plugin;
			}
		}
		return null;
	}

	private void gotoMeetingUI() {
		deactivateActivePluginUI();
		this.meetingUI.putInRootPanel(MAIN_DIV);

	}

	@Override
	public void onMessageEvent(final MessageEvent event) {
		if (event.getType() == EnumMessageEventType.acceptanceReceived
				|| event.getType() == EnumMessageEventType.acceptanceSent) {

			this.meetingUI.removeFromParent();
			startGameUI(event);

		} else if (event.getType() == EnumMessageEventType.loginSuccess) {

			this.loginUI.removeFromParent();
			this.pageTitle.setText("Hello " + this.loginUI.getLogin() + " !");
			gotoMeetingUI();

		} else if (null != this.activePluginUI
				&& event.getType() == EnumMessageEventType.cancelReceived) {

			this.notifyUserQuitDialog.showInfo("Notification", event
					.getMessage().getSender()
					+ " has quited the game.");

		} else if (null != this.activePluginUI
				&& event.getType() == EnumMessageEventType.cancelSent) {

			gotoMeetingUI();
		}

	}

	/**
	 * This is the entry point method.
	 */
	@Override
	public void onModuleLoad() {
		Log.debug("start entry point");

		ApplicationContext.putBean("infoDialog", this.infoDialog);
		ApplicationContext.putBean("errorDialog", this.errorDialog);

		for (IMessagingPlugin plugin : this.plugins) {
			this.meetingUI.getListGameChoices().addItem(plugin.getLabel(),
					plugin.getClass().getName());
		}

		RootPanel.get("title").add(this.pageTitle);

		// this.loginUI.center();
		this.loginUI.putInRootPanel(MAIN_DIV);
	}

	public void showError(final String message) {
		MessagingEntryPoint.this.errorDialog.showError(
				"Sorry, there is a problème!", message);
	}

	/**
	 * 
	 * @param event the event that triggers the game startup.
	 */
	private void startGameUI(final MessageEvent event) {

		String gameChoice = ClientManager.getClientManager().getGameChoice();

		Log.debug("gameChoice: " + gameChoice);
		Log.debug("plugins: " + this.plugins);

		deactivateActivePluginUI();

		IMessagingPlugin activePlugin = findPluginForGame(gameChoice);
		if (null != activePlugin) {
			this.activePluginUI = activePlugin.createUI(event,
					this.clientManager);
			this.activePluginUI.putInRootPanel(MAIN_DIV);
		} else {
			Log.error("No plugin for " + gameChoice);
		}

	}
}